
// <copyright file="AbstractDataReaderStrategy.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The abstractata reader strategy.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Data
{
    using System;
    using System.Collections.Generic;

    /// <summary>
    /// </summary>
    /// <typeparam name="T">
    /// </typeparam>
    public abstract class AbstractDataReaderStrategy<T> : AbstractInitializableAndDisposable, IDataReaderStrategy
    {
        #region Fields

        /// <summary>
        /// The column names.
        /// </summary>
        private List<string> _columnNames;

        /// <summary>
        /// The columns.
        /// </summary>
        private IList<KeyValuePair<string, Type>> _columns;

        /// <summary>
        /// The item array.
        /// </summary>
        private object[] _itemArray;

        #endregion Fields

        #region Public Properties

        /// <summary>
        /// Gets the column names.
        /// </summary>
        public ICollection<string> ColumnNames
        {
            get
            {
                return this._columnNames;
            }
        }

        /// <summary>
        /// Gets or sets the total record count if known.
        /// </summary>
        public long TotalRecordCountIfKnown { get; protected set; }

        #endregion Public Properties

        #region Public Indexers

        /// <summary>
        /// The this.
        /// </summary>
        /// <param name="i">
        /// The i.
        /// </param>
        /// <returns>
        /// The <see cref="object"/>.
        /// </returns>
        public object this[int i]
        {
            get
            {
                return this._itemArray[i];
            }
        }

        #endregion Public Indexers

        #region Public Methods and Operators

        /// <summary>
        /// The get field type.
        /// </summary>
        /// <param name="i">
        /// The i.
        /// </param>
        /// <returns>
        /// The <see cref="Type"/>.
        /// </returns>
        public Type GetFieldType(int i)
        {
            return this._columns[i].Value;
        }

        /// <summary>
        /// The read.
        /// </summary>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public bool Read()
        {
            T current = this.readNextObject();
            if (current != null)
            {
                this.populateItemArray(current, this._itemArray);
                for (int i = 0; i < this._itemArray.Length; i++)
                {
                    if (this._itemArray[i] == null)
                    {
                        this._itemArray[i] = DBNull.Value;
                    }
                }

                return true;
            }

            return false;
        }

        #endregion Public Methods and Operators

        #region Methods

        /// <summary>
        /// The get columns.
        /// </summary>
        /// <returns>
        /// The <see cref="IList{T}"/>.
        /// </returns>
        protected abstract IList<KeyValuePair<string, Type>> getColumns();

        /// <summary>
        /// The initialize protected.
        /// </summary>
        protected override void InitializeProtected()
        {
            this._columns = this.getColumns();
            this._itemArray = new object[this._columns.Count];
            this._columnNames = new List<string>();
            foreach (var kvp in this._columns)
            {
                this._columnNames.Add(kvp.Key);
            }
        }

        /// <summary>
        /// The populate item array.
        /// </summary>
        /// <param name="obj">
        /// The obj.
        /// </param>
        /// <param name="itemArray">
        /// The item array.
        /// </param>
        protected abstract void populateItemArray(T obj, object[] itemArray);

        /// <summary>
        /// The read next object.
        /// </summary>
        /// <returns>
        /// The <see cref="T"/>.
        /// </returns>
        protected abstract T readNextObject();

        #endregion Methods
    }
}